package cn.fscode.code.generator.service.impl;

import cn.fscode.commons.core.page.PageDomain;
import cn.fscode.commons.core.page.TableSupport;
import cn.fscode.commons.tool.core.StringUtils;
import cn.fscode.code.generator.mapper.SysDictItemMapper;
import cn.fscode.code.generator.mapper.SysDictMapper;
import cn.fscode.code.generator.model.po.SysDictItemPO;
import cn.fscode.code.generator.model.po.SysDictPO;
import cn.fscode.code.generator.service.ISysDictItemService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author shenguangyang
 */
@Service
public class SysDictItemServiceImpl implements ISysDictItemService {
    private static final Logger log = LoggerFactory.getLogger(SysDictItemServiceImpl.class);
    @Resource
    private SysDictItemMapper dictItemMapper;

    @Resource
    private SysDictMapper dictMapper;

    private static final Map<String, SysDictItemPO> localDictCache = new ConcurrentHashMap<>();
    /**
     * key: dictCode
     * value
     *  key: dictValue
     *  value: 字典对象
     */
    private static final Map<String, Map<String, SysDictItemPO>> LOCAL_DICT_CACHE_MAP = new ConcurrentHashMap<>();
    private static final List<SysDictItemPO> EMPTY_DICT_ITEM = new ArrayList<>();

    @Override
    public List<SysDictItemPO> listByCode(String dictCode) {
        LambdaQueryWrapper<SysDictPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysDictPO::getDictCode, dictCode);
        SysDictPO sysDictPO = dictMapper.selectOne(queryWrapper);
        if (sysDictPO == null) {
            return EMPTY_DICT_ITEM;
        }

        LambdaQueryWrapper<SysDictItemPO> itemPOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        itemPOLambdaQueryWrapper.eq(SysDictItemPO::getDictId, sysDictPO.getId()).orderByDesc(SysDictItemPO::getCreateTime);
        return dictItemMapper.selectList(itemPOLambdaQueryWrapper);
    }

    @Override
    public Map<String, Map<String, SysDictItemPO>> listByCodes(List<String> codes) {
        Map<String, Map<String, SysDictItemPO>> resp = new HashMap<>(codes.size());
        for (String dictCode : codes) {
            Map<String, SysDictItemPO> data = LOCAL_DICT_CACHE_MAP.get(dictCode);
            if (data == null) {
                data = new HashMap<>();
                List<SysDictItemPO> sysDictItemPOS = listByCode(dictCode);
                for (SysDictItemPO sysDictItemPO : sysDictItemPOS) {
                    data.put(sysDictItemPO.getItemValue(), sysDictItemPO);
                }
                LOCAL_DICT_CACHE_MAP.put(dictCode, data);
            }
            resp.put(dictCode, data);
        }
        return resp;
    }

    @Override
    public SysDictItemPO getByCode(String dictCode, String dictValue) {
        String key = dictCode + "_" + dictValue;
        SysDictItemPO data = localDictCache.get(key);
        if (data != null) {
            return data;
        }
        List<SysDictItemPO> sysDictItemPOList = listByCode(dictCode);
        for (SysDictItemPO sysDictItemPO : sysDictItemPOList) {
            String dictKey = dictCode + "_" + sysDictItemPO.getItemValue();
            localDictCache.put(dictKey, sysDictItemPO);
        }
        // 如果不存在, 就赋值一个空, 防止每次都查db以及redis
        data = localDictCache.get(key);
        if (data == null) {
            localDictCache.put(key, new SysDictItemPO());
        }
        return data;
    }

    @Override
    public SysDictItemPO getById(Long id) {
        return dictItemMapper.selectById(id);
    }

    @Override
    public IPage<SysDictItemPO> page(SysDictItemPO req) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();

        LambdaQueryWrapper<SysDictItemPO> queryWrapper = Wrappers.<SysDictItemPO>lambdaQuery()
                .eq(StringUtils.isNotEmpty(req.getDictCode()), SysDictItemPO::getDictCode, req.getDictCode())
                .eq(Objects.nonNull(req.getDictId()), SysDictItemPO::getDictId, req.getDictId())
                .like(StringUtils.isNotEmpty(req.getItemLabel()), SysDictItemPO::getItemLabel, req.getItemLabel())
                .eq(Objects.nonNull(req.getStatus()), SysDictItemPO::getStatus, req.getStatus())
                .orderByDesc(SysDictItemPO::getSortOrder);
        return dictItemMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);
    }

    @Override
    public void deleteByIds(Long[] dictIds) {
        localDictCache.clear();
        LOCAL_DICT_CACHE_MAP.clear();
        dictItemMapper.deleteBatchIds(Arrays.stream(dictIds).collect(Collectors.toList()));
    }

    @Override
    public void deleteById(Long dictId) {
        localDictCache.clear();
        LOCAL_DICT_CACHE_MAP.clear();
        dictItemMapper.deleteById(dictId);
    }

    @Override
    public int saveDictItem(SysDictItemPO dictData) {
        localDictCache.clear();
        LOCAL_DICT_CACHE_MAP.clear();
        return dictItemMapper.insert(dictData);
    }

    @Override
    public int updateDictItem(SysDictItemPO dictData) {
        localDictCache.clear();
        LOCAL_DICT_CACHE_MAP.clear();
        return dictItemMapper.updateById(dictData);
    }
}
